package com.gopay.common.cipher.algorithm.impl;

import java.io.UnsupportedEncodingException;
import java.util.Arrays;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.LoggerFactory;

import com.gopay.common.cipher.algorithm.CipherAlgorithm;
import com.gopay.common.cipher.algorithm.baseAlgorithm.Cipher3DES;
import com.gopay.common.cipher.algorithm.baseAlgorithm.Decrypt;
import com.gopay.common.cipher.constants.EncryptType;
import com.gopay.common.cipher.constants.SensitiveInfoConstants;
import com.gopay.common.cipher.utils.KeyPropertiesUtils;
import com.gopay.common.cipher.vo.SecurityKeyInfo;

/**
 * 
 * @ClassName: CipherAlgorithmWithCode 
 * @Description: 敏感信息加密类 
 * @author zyt
 * @date 2016年9月2日 下午6:20:19
 */
public class CipherAlgorithmWithCode implements CipherAlgorithm {
	
	private static final String ENCODE_TYPE = "utf-8";

	private static final String MASTER_KEY_NAME = "mkey";
	
	private static org.slf4j.Logger logger = LoggerFactory.getLogger(CipherAlgorithmWithCode.class);
	
	/**
	 * 
	 * @Description: 	使用规定的密钥进行3DES 3KEY加密
	 * @param content   需要加密的内容
	 * @param key		密钥信息
	 * @return			 密文
	 * @author 			zyt
	 */
	public static String encrypt3DES3KEY(String content, String key) throws Exception {
		if(StringUtils.isBlank(content) || StringUtils.isBlank(key)){
			logger.error("明文或data key为空，解密失败");
			return content;
		}
		try {
			byte[] bs = Cipher3DES.encryptBase64(get3DESBytes(key), content.getBytes(ENCODE_TYPE));
			return  new String(bs, ENCODE_TYPE);
		} catch (UnsupportedEncodingException e) {
			logger.error("加密失败，原因：" , e);
			throw new Exception("CipherAlgorithmWithCode-encrypt3DES3KEY() error:" + "不支持的编码方式" );
			//return  content;
		} catch (Exception e1) {
			logger.error("加密失败，原因：" , e1);
			throw new Exception("CipherAlgorithmWithCode-encrypt3DES3KEY() error:" +
					e1.getMessage());
		}
	}

	/**
	 * 
	 * @Description: 	使用规定的密钥，对密文进行3DES解密
	 * @param ciphertext 	密文
	 * @param key	密钥信息
	 * @return 			明文
	 * @author 			zyt
	 */
	public static String decrypt3DES3KEY(String ciphertext, String key) throws Exception {
		if (StringUtils.isNotEmpty(ciphertext) && StringUtils.isNotEmpty(key)) {
			try {
				byte[] ciphertextBytes = ciphertext.getBytes(ENCODE_TYPE);
				byte[] certNoByte = Cipher3DES.decryptBase64(get3DESBytes(key), ciphertextBytes);
				return new String(certNoByte,ENCODE_TYPE);
			} catch (UnsupportedEncodingException e) {
				logger.error("解密失败，原因：" , e);
				throw new Exception("CipherAlgorithmWithCode-decrypt3DES3KEY() error:" +
						"不支持的编码方式");
				//return ciphertext;
			} catch (Exception e1) {
				logger.error("加密失败，原因：" , e1);
				throw new Exception("CipherAlgorithmWithCode-decrypt3DES3KEY() error:" +
						e1.getMessage());
			}
		} else {
			logger.error("解密失败，原因：密文或data key为空");
			throw new Exception("CipherAlgorithmWithCode-decrypt3DES3KEY() error:" + "密钥或原文为空" );
		}
		//return ciphertext;
	}
	
	
	private static byte[] get3DESBytes(String key) throws Exception{
		try {
			if (key.length() == 24) {
				return key.getBytes(ENCODE_TYPE);
			} else {
				return Arrays.copyOf(key.getBytes(ENCODE_TYPE), 24);
			}
		} catch (UnsupportedEncodingException e) {
			logger.error("获取密钥字节失败，不支持的编码方式");
			throw new Exception("CipherAlgorithmWithCode-get3DESBytes() error" 
					+ "不支持的编码方式");
			//return null;
		}
	}

	/**
	 *
	 * @Description: 		传入密文，根据密文前缀判断使用的何种加密方式
	 * @param cipherText	密文
	 * @return 				加密方式
	 * @author 				zyt
	 */
	/*public static EncryptType getEncryptType(String cipherText) {
		
		if (StringUtils.isNotEmpty(cipherText)) {
			if (cipherText.startsWith(SensitiveInfoConstants.ENCRYPT_MARK_3DES_2KEY)) {
				//3des 2key加密的前缀
				return EncryptType.THREE_DES_TWO_KEYS;
			} else if (cipherText.startsWith(SensitiveInfoConstants.ENCRYPT_MARK_3DES_3KEY)) {
				//3des 3key加密的前缀
				return EncryptType.THREE_DES_THREE_KEYS;
			} else if (cipherText.startsWith(SensitiveInfoConstants.ENCRYPT_MARK_DES)) {
				//des加密的前缀
				return EncryptType.DES;
			} else if(StringUtils.contains(cipherText, SensitiveInfoConstants.ENCRYPT_COMMON_MARK)){
				logger.error("未知的加密方式，无法解密");
			}
		}

		return null;
	}*/
	
	
	public static String byteArr2HexStr(byte[] bytea) throws Exception {  
        String sHex = "";  
        int iUnsigned = 0;  
        StringBuffer sbHex = new StringBuffer();  
        for (int i = 0; i < bytea.length; i++) {  
            iUnsigned = bytea[i];  
            if (iUnsigned < 0) {  
                iUnsigned += 256;  
            }  
            if (iUnsigned < 16) {  
                sbHex.append("0");  
            }  
            sbHex.append(Integer.toString(iUnsigned, 16));  
        }  
        sHex = sbHex.toString();  
        return sHex;  
    }  
	
	/**
	 * 
	 * @Description: 	获取master key。
	 * 					暂时从应用服务器获取，后续可能需要修改为从加密机获取 
	 * @return 			master key
	 * @author			zyt
	 * @throws 			Exception
	 */
	private static String getMasterKey() throws Exception {
		String key = KeyPropertiesUtils.getValueBykey(MASTER_KEY_NAME);
		try {
			Decrypt d = new Decrypt();
			return d.decrypt(key);
		} catch (Exception e) {
			logger.error("获取master key失败，原因：" , e);
			throw new Exception("CipherAlgorithmWithCode-getMasterKey() error"
					+ "decrypt master key failed");
		}
		//return null;
	}
	
	/**
	 * 
	 * @Description: 		为加密的data key进行解密 
	 * @param cipherKey		data key的密文
	 * @param masterKey		master key
	 * @param encryptType	加密方式
	 * @return 				data key明文
	 * @author zyt
	 */
	private static String decryptDataKey(String cipherKey, String masterKey, EncryptType encryptType) throws Exception{
		if (encryptType == EncryptType.THREE_DES_THREE_KEYS) {
			cipherKey = cipherKey.replace(SensitiveInfoConstants.ENCRYPT_MARK_3DES_3KEY 
					+ SensitiveInfoConstants.ENCRYPT_COMMON_MARK, "");
			try {
				return decrypt3DES3KEY(cipherKey, masterKey);
			} catch (Exception e) {
				logger.error("解密data key失败，原因：" , e);
				throw new Exception("CipherAlgorithmWithCode-decryptDataKey() error:" +
						 e.getMessage());
			}
		} else {
			return cipherKey;
		}
	}
	

	@Override
	public String decrypt(String cipherContent, SecurityKeyInfo keyInfo) throws Exception {
		String resText;
		String masterKey = getMasterKey();
		//如果获取密钥失败，则返回原字符串
		if(keyInfo != null && StringUtils.isNotBlank(masterKey)){
			String dataKey = decryptDataKey(keyInfo.getKeyContent(), masterKey, keyInfo.getEncryptType());
			resText = decrypt3DES3KEY(cipherContent, dataKey);
		} else {
			logger.error("data key或master key为空，解密失败，返回原文");
			resText = cipherContent;
		}
		
		return resText;
	}

	@Override
	public String encrypt(String content, SecurityKeyInfo keyInfo) throws Exception {
		if(keyInfo != null){
			String masterKey = getMasterKey();
			if(StringUtils.isBlank(masterKey)){
				logger.error("master key为空，加密失败");
				return content;
			}
			String dataKey = decryptDataKey(keyInfo.getKeyContent(), masterKey, keyInfo.getEncryptType());
			
			return encrypt3DES3KEY(content, dataKey);
		} else {
			logger.error("data key为空，加密失败，返回原文");
			return content;
		}
	}
	
	public static void main(String[] args) throws Exception {
		// System.out.println(encrypt(key,content));
		String DateKey = "91sj!XwuGMcuEl^J$#l6AhAW";
		String masterKey = "DQoOqqPLyVjdfD%hsxhgDM#0";
		/*String ciphertext = "01-12月-22 12.00.00.000000 上午";
		String masterKey = "DQoOqqPLyVjdfD%hsxhgDM#0";
		String testKey1 = "C83C87A75B3A997B0A078A97BAA0300B70B1BC6F1E5371D6";
		long startMills = System.currentTimeMillis();
		for(int i = 0; i < 10000; i++){
			System.out.println("name:" + i + encrypt3DES3KEY("testtestesttestestes" + i,"91sj!XwuGMcuEl^J$#l6AhAW"));
		}
		long endMills = System.currentTimeMillis();
		System.out.println("last times:" + (endMills - startMills));*/
		System.out.println(encrypt3DES3KEY(DateKey,masterKey));
		System.out.println(decrypt3DES3KEY("n/KXYhGYUDmf8pdiEZhQOcMjZrtClDOn", DateKey));
		/*String CnTe = "test";
		try {
			byte[] bytes = CnTe.getBytes("UTF-16");
			int len = bytes.length;
			System.out.println(len);
		} catch (Exception e) {
			e.printStackTrace();
		}*/
		//String testKey2 = "7AAD79D6157F10452CBCB30";
		/*String data = "passwordpassword";
		String encrypteData = encrypt3DES3KEY(data,DateKey);
		System.out.println("name:" + encrypteData);
		byte[] enDaB = encrypteData.getBytes();
		System.out.println("enDaB length:" + enDaB.length);
		byte[] enDaBBase = Base64.decode(enDaB);
		System.out.println("enDaBBase length:" + enDaBBase.length);
		try {
			System.out.println("enDaBBase:" + byteArr2HexStr(enDaBBase));
		} catch (Exception e) {
			e.printStackTrace();
		}
		System.out.println("name:" + decrypt3DES3KEY("Z21ujkJbbNbDI2a7QpQzpw==",DateKey));*/
		//System.out.println("name:" + encrypt3DES3KEY("1234567980",testKey2));
	/*	String name = "赵亚亭赵亚亭";
		String num = "6217003400000609902";
		String cipherDataKey = "s2qQ+nqgE4lkidqYlge0BU7IHinZSCZoDvls+mRRU4A=";
		String cipherT = "6EvyErEVfFeUjc6FHq1NFgTHtInEYpHnd+fRXSlzhVXtHi4ij8Bdjw==";
		System.out.println("datekey:" + encrypt3DES3KEY(DateKey,"DQoOqqPLyVjdfD%hsxhgDM#0"));
		System.out.println("name:" + encrypt3DES3KEY(name,"91sj!XwuGMcuEl^J$#l6AhAW"));
		System.out.println("num:" + encrypt3DES3KEY(num,"91sj!XwuGMcuEl^J$#l6AhAW"));
		System.out.println("ciphertext:" + encrypt3DES3KEY(ciphertext,DateKey));
		System.out.println(decrypt3DES3KEY("Vo3jWwxPWlL1fP52yquWXdyBso4Z/hlU",DateKey));
		System.out.println(decrypt3DES3KEY("s2qQ+nqgE4lkidqYlge0BU7IHinZSCZoDvls+mRRU4A=",masterKey));
		System.out.println(decrypt3DES3KEY("s2qQ+nqgE4lkidqYlge0BU7IHinZSCZoDvls+mRRU4A=",masterKey));
		System.out.println(decrypt3DES3KEY("wSB+cyp/ul8mzLtHXvx+JeM0KDw/yzJwjX8CRxLac2k=","Nu7WXBJIpqMZRGnxpq7d2~uM"));*/
		//System.out.println(decrypt3DES3KEY("5TBXCwg8NHfvj/WoyKz60QDV6KzkWGeGkH6q14k/Gts==",DateKey));
		//System.out.println("name:" + encrypt3DES3KEY("aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeaaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeea",DateKey));
		//System.out.println(decrypt3DES3KEY(cipherDataKey,"www.portal2.gopay.com.cn"));
		//num.replace("6217", "7126");
		//System.out.println(num);
	}

}
